package com.qumitech.visualnovel.console.excel;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.qumitech.visualnovel.component.annotation.ExcelAnnotation;
import com.qumitech.visualnovel.component.util.CommonUtil;
import com.qumitech.visualnovel.component.util.TimeUtils;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * //                       _oo0oo_
 * //                      o8888888o
 * //                      88" . "88
 * //                      (| -_- |)
 * //                      0\  =  /0
 * //                    ___/`---'\___
 * //                  .' \\|     |// '.
 * //                 / \\|||  :  |||// \
 * //                / _||||| -:- |||||- \
 * //               |   | \\\  -  /// |   |
 * //               | \_|  ''\---/''  |_/ |
 * //               \  .-\__  '-'  ___/-. /
 * //             ___'. .'  /--.--\  `. .'___
 * //          ."" '<  `.___\_<|>_/___.' >' "".
 * //         | | :  `- \`.;`\ _ /`;.`/ - ` : | |
 * //         \  \ `_.   \_ __\ /__ _/   .-` /  /
 * //     =====`-.____`.___ \_____/___.-`___.-'=====
 * //                       `=---='
 * //
 * //
 * //     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * //
 * //               佛祖保佑         永无BUG
 * <p>
 * com.qumitech.visualnovel.console.excel
 * Created on 2020/9/30.
 */
class ExcelWriter {

    private List<String[]> keys;
    private List<String> headers;
    private Map<String, Integer> units;
    private Map<String, Map<String, String>> states;
    private  int sheetIndex = 0;
    private  int rowIndex = 0;
    private  SXSSFWorkbook workbook;
    private File file;
    private SXSSFRow row;
    private SXSSFSheet sheet;

    ExcelWriter(File file, ExportExcel config) {
        setup(config);
        this.workbook = new SXSSFWorkbook(1000);
        this.file = file;
    }

    public void flush() {
        FileOutputStream  outputStream = null;
        try {
            outputStream = new FileOutputStream(this.file);
            this.workbook.write(outputStream);
        } catch (IOException e) {
        } finally {
            this.workbook.dispose();
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                }
            }
        }
    }

    private void setup(ExportExcel config) {
        // 处理需要转换单位的字段.
        Map<String, Integer> units = new HashMap<>();
        for (UnitField unitField : config.unitFields()) {
            units.put(unitField.key(), unitField.unit());
            units.put(CommonUtil.camelToUnderline(new StringBuffer(unitField.key())).toString(), unitField.unit());
        }

        // 处理需要按状态值处理的字段
        Map<String, Map<String, String>> states = new HashMap<>();
        for (StateField stateField : config.stateFields()) {
            Map<String, String> fieldStates = new HashMap<>();
            for (State state : stateField.states()) {
                fieldStates.put(state.state(), state.display());
            }
            states.put(stateField.key(), fieldStates);
            states.put(CommonUtil.camelToUnderline(new StringBuffer(stateField.key())).toString(), fieldStates);
        }


        List<String[]> ks = new ArrayList<>();
        List<String> vs = new ArrayList<>();


        if (config.itemCls() != ExportExcel.DefaultClass.class) {
            Field[] fields = config.itemCls().getDeclaredFields();
            for (Field field : fields) {
                ExcelAnnotation excelAnnotation = field.getAnnotation(ExcelAnnotation.class);
                if (excelAnnotation != null) {
                    String export = excelAnnotation.value();
                    String fieldName = field.getName();
                    String[] key = new String[]{fieldName, CommonUtil.camelToUnderline(new StringBuffer(fieldName)).toString()};
                    ks.add(key);
                    vs.add(export);
                }
            }
        } else {
            ks = Arrays.asList(config.itemKeys()).stream().map(item -> new String[]{item, CommonUtil.camelToUnderline(new StringBuffer(item)).toString()}).collect(Collectors.toList());
            vs = Arrays.asList(config.itemNames());
        }
        this.keys = ks;
        this.headers = vs;
        this.units = units;
        this.states = states;
    }


    public void write(JSONArray items) {
        if (items.isEmpty()) {
            return;
        }
        if (keys.isEmpty()) {
            // 如果keys是空的, 那么直接用json结果的key 作为key.
            Set<String> keySet = items.getJSONObject(0).keySet();
            headers = new ArrayList<>(keySet);
            keys = headers.stream().map(item -> new String[]{item}).collect(Collectors.toList());
        }
        for (int i = 0; i < items.size(); i++) {
            if ((rowIndex + i) % 60000 == 0) {
                sheet = workbook.createSheet("导出数据" + sheetIndex);
                sheet.setDefaultColumnWidth(20);
                sheetIndex++;
                row = sheet.createRow(0);
                //标题行
                for (int k = 0; k < keys.size(); k++) {
                    SXSSFCell cell = row.createCell(k);
                    cell.setCellValue(new XSSFRichTextString(headers.get(k)));
                }
                rowIndex = 1;
            }
            row = sheet.createRow(rowIndex++);
            JSONObject item = items.getJSONObject(i);
            for (int k = 0; k < keys.size(); k++) {
                SXSSFCell cell = row.createCell(k);
                String[] key = keys.get(k);
                Object value = "";
                for (String s : key) {
                    if (item.containsKey(s)) {
                        value = generifyValue(units, states, item.get(s), s);
                        break;
                    }
                }
                cell.setCellValue(new XSSFRichTextString(String.valueOf(value)));
            }
        }
    }

    private Object generifyValue(Map<String, Integer> units, Map<String, Map<String, String>> states, Object value, String s) {
        if (value instanceof Long) {
            if (s.toLowerCase().contains("time")) {
                value = TimeUtils.getTime((Long) value, "yyyy-MM-dd HH:mm:ss");
            } else if (s.toLowerCase().contains("date")) {
                value = TimeUtils.getTime((Long) value, "yyyy-MM-dd");
            }
        }else if (value instanceof Boolean) {
            value = (Boolean) value ? "是" : "否";
        }
        if (units.containsKey(s)) {
            int divid = units.get(s);
            if (value instanceof Number) {
                value = Double.valueOf(String.valueOf(value)) / divid;
            }
        }
        if (states.containsKey(s)) {
            Map<String, String> fieldStates = states.get(s);
            String str = String.valueOf(value);
            if (fieldStates.containsKey(str)) {
                value = fieldStates.get(str);
            }
        }
        return value;
    }
}
